// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_PLAYER_RENDERER_H_
#define CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_PLAYER_RENDERER_H_

#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/unguessable_token.h"
#include "content/common/content_export.h"
#include "content/public/browser/render_frame_host.h"
#include "media/base/android/media_player_bridge.h"
#include "media/base/android/media_player_manager.h"
#include "media/base/demuxer_stream_provider.h"
#include "media/base/media_log.h"
#include "media/base/renderer.h"
#include "media/base/renderer_client.h"
#include "url/gurl.h"

namespace content {

// MediaPlayerRenderer bridges the media::Renderer and Android MediaPlayer
// interfaces. It owns a MediaPlayerBridge, which exposes c++ methods to call
// into a native Android MediaPlayer.
//
// Each MediaPlayerRenderer is associated with one MediaPlayerRendererClient,
// living in WMPI in the Renderer process.
//
// N.B: MediaPlayerRenderer implements MediaPlayerManager, since
// MediaPlayerBridge is tightly coupled with the manager abstraction.
// |player_id| is ignored in all MediaPlayerManager calls, as there is only one
// MediaPlayer per MediaPlayerRenderer.
//
// TODO(tguilbert): Remove the MediaPlayerManager implementation and update
// MediaPlayerBridge, once WMPA has been deleted. See http://crbug.com/580626
class CONTENT_EXPORT MediaPlayerRenderer : public media::Renderer,
                                           public media::MediaPlayerManager {
public:
    // Permits embedders to handle custom urls.
    static void RegisterMediaUrlInterceptor(
        media::MediaUrlInterceptor* media_url_interceptor);

    explicit MediaPlayerRenderer(content::RenderFrameHost* render_frame_host);

    ~MediaPlayerRenderer() override;

    // media::Renderer implementation
    void Initialize(media::DemuxerStreamProvider* demuxer_stream_provider,
        media::RendererClient* client,
        const media::PipelineStatusCB& init_cb) override;
    void SetCdm(media::CdmContext* cdm_context,
        const media::CdmAttachedCB& cdm_attached_cb) override;
    void Flush(const base::Closure& flush_cb) override;
    void StartPlayingFrom(base::TimeDelta time) override;

    // N.B: MediaPlayerBridge doesn't support variable playback rates (but it
    // could be exposed from MediaPlayer in the future). For the moment:
    // - If |playback_rate| is 0, we pause the video.
    // - For other |playback_rate| values, we start playing at 1x speed.
    void SetPlaybackRate(double playback_rate) override;
    void SetVolume(float volume) override;
    base::TimeDelta GetMediaTime() override;

    // media::MediaPlayerManager implementation
    media::MediaResourceGetter* GetMediaResourceGetter() override;
    media::MediaUrlInterceptor* GetMediaUrlInterceptor() override;
    void OnTimeUpdate(int player_id,
        base::TimeDelta current_timestamp,
        base::TimeTicks current_time_ticks) override;
    void OnMediaMetadataChanged(int player_id,
        base::TimeDelta duration,
        int width,
        int height,
        bool success) override;
    void OnPlaybackComplete(int player_id) override;
    void OnMediaInterrupted(int player_id) override;
    void OnBufferingUpdate(int player_id, int percentage) override;
    void OnSeekComplete(int player_id,
        const base::TimeDelta& current_time) override;
    void OnError(int player_id, int error) override;
    void OnVideoSizeChanged(int player_id, int width, int height) override;
    media::MediaPlayerAndroid* GetFullscreenPlayer() override;
    media::MediaPlayerAndroid* GetPlayer(int player_id) override;
    bool RequestPlay(int player_id,
        base::TimeDelta duration,
        bool has_audio) override;

    // Registers a request in the content::ScopedSurfaceRequestManager, and
    // returns the token associated to the request. The token can then be used to
    // complete the request via the gpu::ScopedSurfaceRequestConduit.
    // A completed request will call back to OnScopedSurfaceRequestCompleted().
    //
    // NOTE: If a request is already pending, calling this method again will
    // safely cancel the pending request before registering a new one.
    base::UnguessableToken InitiateScopedSurfaceRequest();
    void OnScopedSurfaceRequestCompleted(gl::ScopedJavaSurface surface);

private:
    void CreateMediaPlayer(const media::MediaUrlParams& params,
        const media::PipelineStatusCB& init_cb);

    // Used when creating |media_player_|.
    void OnDecoderResourcesReleased(int player_id);

    // Cancels the pending request started by InitiateScopedSurfaceRequest(), if
    // it exists. No-ops otherwise.
    void CancelScopedSurfaceRequest();

    RenderFrameHost* render_frame_host_;
    media::RendererClient* renderer_client_;

    std::unique_ptr<media::MediaPlayerBridge> media_player_;

    // Current duration of the media.
    base::TimeDelta duration_;

    // Indicates if a serious error has been encountered by the |media_player_|.
    bool has_error_;

    gfx::Size video_size_;

    base::UnguessableToken surface_request_token_;

    std::unique_ptr<media::MediaResourceGetter> media_resource_getter_;

    // NOTE: Weak pointers must be invalidated before all other member variables.
    base::WeakPtrFactory<MediaPlayerRenderer> weak_factory_;

    DISALLOW_COPY_AND_ASSIGN(MediaPlayerRenderer);
};

} // namespace content

#endif // CONTENT_BROWSER_MEDIA_ANDROID_MEDIA_PLAYER_RENDERER_H_
